﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using IceZero.DataStore.Models;
using NHibernate.Criterion;

namespace IceZero.DataStore
{
    public class UserDataStore : DataStoreBase<User>
    {
        private static OnlineUserContainer _onlineUserContainer;
        private static object _onlineUserContainerLock = new();

        /// <summary>
        /// 在线用户容器
        /// </summary>
        public static OnlineUserContainer OnlineUserContainer
        {
            get
            {
                if (_onlineUserContainer == null)
                {
                    lock (_onlineUserContainerLock)
                    {
                        if (_onlineUserContainer == null)
                        {
                            _onlineUserContainer = new OnlineUserContainer();
                        }
                    }
                }

                return _onlineUserContainer;
            }
        }

        /// <summary>
        /// 获取所有的用户列表
        /// </summary>
        /// <returns></returns>
        public List<User> GetUserList()
        {
            return base.QueryAll();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<User> GetOnlineUserList()
        {
            return OnlineUserContainer.Values.ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string AddUser(User user)
        {
            return base.Save<string>(user);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public void DeleteUser(User user)
        {
            base.Delete(user);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception">user is not exist or account and password is error</exception>
        public string Login(string account, string password)
        {
            var user = GetUserInfoByAccountAndPassword(account, password);
            if (user == null)
            {
                throw new Exception("user is not exist or account and password is error");
            }
            var token = GenToken(account, password);
            if (!OnlineUserContainer.ContainsKey(token))
            {
                OnlineUserContainer.Add(token, user);
            }
            return token;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool Logout(string token)
        {
            if (!OnlineUserContainer.ContainsKey(token))
            {
                return false;
            }
            OnlineUserContainer.Remove(token);
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool IsLogin(string token)
        {
            return OnlineUserContainer.ContainsKey(token);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        private string GenToken(string account, string password)
        {
            byte[] accountBytes = Encoding.UTF8.GetBytes(account);
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
            MD5 md5 = new MD5CryptoServiceProvider();
            var allBytes = new byte[accountBytes.Length + passwordBytes.Length];
            accountBytes.CopyTo(allBytes, 0);
            passwordBytes.CopyTo(allBytes, 0);
            byte[] accountResult = md5.ComputeHash(allBytes);
            var token = BitConverter.ToString(accountResult).Replace("-", "").ToLower();
            return token;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        private User GetUserInfoByAccountAndPassword(string account, string password)
        {
            User user = null;
            NHibernateHelper.UseSessionWithTransactionWatchRawSql(session =>
            {
                var criteria = session.CreateCriteria<User>();
                criteria.Add(Restrictions.Eq("Account", account))
                .Add(Restrictions.Eq("Password", password));
                user = criteria.SetFirstResult(0).SetMaxResults(1).UniqueResult<User>();
            });

            return user;
        }

        public User GetAdmin()
        {
            return QueryById("a101000000000000000000000abc123");
        }

        public User GetRoot()
        {
            return QueryById("a101000000000000000000000abc456");
        }
    }
}
